/***********************************************************************************
 @file   
 @author
 @attention
 ***********************************************************************************/
#include "device_adxl345.h"
/***********************************************************************************
*@para  
***********************************************************************************/
_adxl345_obj adxl345;
/***********************************************************************************
*@param  adx1345写单个寄存器接口
***********************************************************************************/
void adxl345_write_reg(uint8_t addr,uint8_t data) 
{
    I2C_MasterWriteData(M0P_I2C1, addr, &data, 1);    
}
/***********************************************************************************
*@param adx1345读单个寄存器接口
***********************************************************************************/
uint8_t adxl345_read_reg(uint8_t addr) 		
{
    uint8_t data;
    I2C_MasterReadData(M0P_I2C1, addr, &data, 1);
    return data;
}
/***********************************************************************************
*@brief adxl345 初始化 iic和int端口
***********************************************************************************/
void adxl345_gpio_init(void)
{
    //---------------------------------------------输入上拉并配置下降沿中断用于唤醒
    //---------------------------------------------IIC INIT
    App_I2cCfg();  
    I2C_SetFunc(M0P_I2C1,I2cModule_En);        
    I2C_SetFunc(M0P_I2C1,I2cStart_En);   
}
/***********************************************************************************
*@brief ADXL345加速度传感器初始化函数
***********************************************************************************/
uint8_t adxl345_init(void)
{	
    adxl345_gpio_init();
    uint8_t id, val;
   
    uint8_t retry_count = 5;//重置计数器
    
    //--------------------------------------区别产品类别
    for (uint8_t i = 0; i < retry_count; i++) 
    {
        id = adxl345_read_reg(DEVICE_ID); // 读取器件ID，ADXL345的器件ID应为0xE5
        if (id == 0xE5){ 
//            adxl345.flag = 1;//带有充电，adxl345，语音播报产品
            printf("adxl345 init success\r\n");
            break;
        }
        else{
            adxl345.flag = 0;//正常初版电池款
            printf("adxl345 init attempt %d failed, retrying...\r\n", i+1);
        }
        delay_ms(20); 
    }
   
    __disable_irq(); 
    //配置DATA_FORMAT寄存器（高电平中断输出，13位全分辨率，右对齐，2g量程）
    adxl345_write_reg(DATA_FORMAT, 0x00);
    // 配置BW_RATE寄存器 数据输出速度为100Hz
    adxl345_write_reg(BW_RATE, 0x17);   
    // 配置POWER_CTL寄存器（测量模式）
    adxl345_write_reg(POWER_CTL, 0x08);
    // 配置THRESH_ACT寄存器（活动阈值）
    adxl345_write_reg(THRESH_ACT,system_data.mobility);//设置唤醒阈值0x00为关  0x10 0x08
    // 配置ACT_INACT_CTL寄存器（活动轴使能）
    adxl345_write_reg(ACT_INACT_CTL, 0xff);//与源程序不同
    // 配置INT_ENABLE寄存器（使能活动中断）
    adxl345_write_reg(INT_ENABLE, 0x10);
    // 映射中断源到INT0
    adxl345_write_reg(INT_MAP,0x00);  
    // 配置偏移校准寄存器（OFSX/OFSY/OFSZ）
    adxl345_write_reg(OFSX, 0x00);  
    adxl345_write_reg(OFSY, 0x00);
    adxl345_write_reg(OFSZ, 0x00);

    // 读取INT_SOURCE寄存器状态
    adxl345.status = adxl345_read_reg(INT_SOURCE);
    __enable_irq();  // 重新开启中断
    return 0;        // 初始化成功       								  
} 
/***********************************************************************************
*@brief ADXL345 读取ADXL345三个轴的数据
***********************************************************************************/
void adxl345_read_xyz(short *x,short *y,short *z)
{
	uint8_t buf[6];	
    
    buf[0] = adxl345_read_reg(DATA_X0);
    buf[1] = adxl345_read_reg(DATA_X1);
    
    // Read Y-axis data (LSB first, then MSB)
    buf[2] = adxl345_read_reg(DATA_Y0);
    buf[3] = adxl345_read_reg(DATA_Y1);
    
    // Read Z-axis data (LSB first, then MSB)
    buf[4] = adxl345_read_reg(DATA_Z0);
    buf[5] = adxl345_read_reg(DATA_Z1);
    
	*x=(short)(((uint16_t)buf[1]<<8)+buf[0]); 	//DATA_X1为高位有效字节    
	*y=(short)(((uint16_t)buf[3]<<8)+buf[2]); 	//DATA_Y1为高位有效字节  	    
	*z=(short)(((uint16_t)buf[5]<<8)+buf[4]); 	//DATA_Z1为高位有效字节  	   
}
/***********************************************************************************
*@brief 读取ADXL345三个轴的偏移数据
***********************************************************************************/
void adxl345_read_xyz_run(char *x,char *y,char *z)
{
	uint8_t buf[4];		
    buf[0] = adxl345_read_reg(OFSX);
    buf[1] = adxl345_read_reg(OFSY);
    buf[2] = adxl345_read_reg(OFSZ);

	*x=buf[0]; 	//DATA_X1为高位有效字节    
	*y=buf[1]; 	//DATA_Y1为高位有效字节  	    
	*z=buf[2]; 	//DATA_Z1为高位有效字节  	   
}
/***********************************************************************************
*@brief 读取ADXL345的数据并做滤波处理，读times次再取平均值
***********************************************************************************/
void adxl345_read_average(short *x,short *y,short *z,uint8_t times)
{
	uint8_t i;
	short tx,ty,tz;
	*x=0; *y=0; *z=0;
	if(times){
		for(i=0;i<times;i++){
			adxl345_read_xyz(&tx,&ty,&tz);
			*x+=tx;	*y+=ty;	*z+=tz;
			delay_ms(5);
		}
		*x/=times; *y/=times; *z/=times;
	}
}  
///***********************************************************************************
//*@brief 计算ADXL345角度，x/y/表示各方向上的加速度分量，dir表示要获得的角度
//***********************************************************************************/
//short adxl345_get_angle(float x,float y,float z,uint8_t dir){
//	float temp;
// 	float res=0;	//弧度值
//	switch(dir){
//		case 0:		//0表示与Z轴的角度
// 			temp=sqrt((x*x+y*y))/z;
// 			res=atan(temp);
// 			break;
//		case 1:		//1表示与X轴的角度
// 			temp=x/sqrt((y*y+z*z));
// 			res=atan(temp);
// 			break;
// 		case 2:		//2表示与Y轴的角度
// 			temp=y/sqrt((x*x+z*z));
// 			res=atan(temp);
// 			break;
// 	}
//	return res*180/3.14;	//返回角度值
//}
/***********************************************************************************
 * @brief  根据加速度计数据计算与指定轴的角度（单位：度）
 * @param  x,y,z: 加速度计的X/Y/Z轴原始数据
 * @param  dir: 计算角度的方向（0=Z轴，1=X轴，2=Y轴）
 * @retval 角度值（短整型）
 ***********************************************************************************/
short adxl345_get_angle(float x, float y, float z, uint8_t dir)
{
    float temp;
    float res = 0;  // 弧度值
    
    switch(dir)
    {
        case 0: 
            temp = (x*x + y*y);  
            if(z != 0) temp = sqrtf(temp) / z;  
            else temp = 0;
            res = atanf(temp);  
            break;
            
        case 1:  
            temp = (y*y + z*z);  
            if(temp != 0) temp = x / sqrtf(temp);  
            else temp = 0;
            res = atanf(temp);  
            break;
            
        case 2:  
            temp = (x*x + z*z); 
            if(temp != 0) temp = y / sqrtf(temp);  // 使用sqrtf优化浮点sqrt
            else temp = 0;
            res = atanf(temp);  // 使用atanf优化浮点atan
            break;
    }   
    return (short)(res * 57.2957795f);  // 弧度转角度(180/PI≈57.2957795)
}
/***********************************************************************************
*@brief ADXL345 检测角度变化，超过阈值触发报警
***********************************************************************************/
void adxl345_process(void)
{
    static short xang_last,yang_last,zang_last,xang,yang,zang;
    static uint8_t first_in=0;
    short x,y,z;
    adxl345_read_average(&x,&y,&z,3); 
    xang=adxl345_get_angle(x,y,z,1);
    yang=adxl345_get_angle(x,y,z,2);
    zang=adxl345_get_angle(x,y,z,0);
    
    //printf("xang:%d|yang:%d|zang:%d\r\n",xang,yang,zang); 
    
    if(adxl345.move_alarm)
    {
        adxl345.move_alarm=0;
        adxl345.status = adxl345_read_reg(INT_SOURCE);//一定要读，不然中断失效
        if((abs(xang-xang_last)>system_data.angle_alarm)||(abs(yang-yang_last)>system_data.angle_alarm)||(abs(zang-zang_last)>system_data.angle_alarm))
        {
            adxl345.global_alarm=1;
        }
    }
    xang_last=xang;
    yang_last=yang;
    zang_last=zang;
    // 首次运行时初始化报警标志
    if(first_in==0)
    {
        first_in=1;
        adxl345.global_alarm=0;
    }
}
